Table des matières
Sauvegarde Yunohost avec Restic
Configuration du serveur cible
Configuration du serveur source
Vérifiez que tout fonctionne jusque-là
| On m’a suggéré de créer un paquet sur le forum suite à cette publication, c’est chose faite! Ce qui suit est toujours vrai mais ce sera bien plus simple d’utiliser le paquet, qui de plus intègre la planification des vérifications des dépôts. Il est encore expérimental donc pour l’installer: yunohost app install https://github.com/YunoHost-Apps/restic_ynh.git Pour l’installer: yunohost app install restic ou le choisir dans la liste depuis l’interface web. |
Cette procedure est une adaptation de How to backup your YunoHost server on another server. J’ai décidé d’utiliser restic au lieu de borg parce que:
•.J’ai essayé la version packagée de borg pour Yunohost et je n’ai pas réussi à la faire fonctionner
•.Je ne voulais pas installer de dépendance sur mon serveur cible, restic ne nécessite qu’un accès à un serveur sftp ce que fait n’importe quelle machine avec le paquet openssh-server.
•.restic dispose des mêmes fonctionalités que borg (du moins celles qui m’intéressent)
•.restic étant écrit en go, l’installation se résume à la copie d’un fichier, c’est très simple et évite d’avoir à installer plusieurs autres paquets sur mon serveur yunohost.
•.j’avais déjà utilisé restic et j’en étais content
•.Je peux le faire, tout simplement. Ça fait une alternative de plus aux options existantes. Chacun peut choisir celle qu’il préfère :)
L’objectif ici est de sauvegarder mon instance Yunohost quotidiennement et de tirer partie des fonctionalités de déduplication et de snapshots de restic pour garder de multiples versions de mes configurations et fichiers.
Tout au long de cette procédure, on partira du postulat suivant:
•.Méthode de sauvegarde: myrestic
•.Server hébergeant l’instance Yunohost à sauvegarder
•.nom mysourceserver
•.adresse mysourceserver.mysourcedomain.tld
•.clé privée ssh /root/.ssh/id_rsa_restic
•.clé publique ssh /root/.ssh/id_rsa_restic.pub
•.Serveur vers lequel on veut sauvegarder Yunohost:
•.nom mytargetserver
•.adresse mytargetserver.mytargetdomain.tld
•.utilisateur sftp mytargetuser
•.port sftp 2222
•.répertoire de stockage des sauvegardes: /home/backup/mysourceserver.mysourcedomain.tld
Pensez bien à adapter ces informations à votre cas dans tout ce qui va suivre
| Vous pouvez aussi utiliser un répertoire local (sur un disque dur externe monté par exemple) et bénéficier quand même des fonctionalités de restic. Dans ce cas vous pouvez vous passer de la configuration du serveur cible, il suffit simplement de s’assurer que le répertoire cible de la sauvegarde existe. Vous n’aurez pas non plus besoin de configurer ssh. |
Sur le serveur où vous voulez envoyer vos sauvegardes:
•.Créez l’utilisateur mytargetuser et définissez son mot de passe. Je vous renvoie à la documentation de votre distribution GNU/Linux pour cela mais pour indication ça devrait ressembler à quelque chose comme ça:
# en tant que root ou alors à précéder d'un `sudo `
useradd -m mytargetuser
passwd mytargetuser
•.Créez le répertoire de destination des sauvegardes et définissez le propriétaire à mytargetuser
mkdir /home/backup/mysourceserver.mysourcedomain.tld
chown mytargetuser: /home/backup/mysourceserver.mysourcedomain.tld
| On pourrait améliorer la sécurité:
|
Sur le serveur Yunohost à sauvegarder (tout ceci doit être fait en tant que root):
•.Installer restic
cd /tmp
wget https://github.com/restic/restic/releases/download/v0.9.6/restic_0.9.6_linux_amd64.bz2
bunzip2 restic_*.bz2 -c > /usr/local/bin/restic
chmod +x /usr/local/bin/restic
| Choisissez la dernière version correspondant à votre architecture sur cette page (linux_arm64 si vous êtes sur Raspberry Pi par exemple). |
| Vous pouvez choisir n’importe quelle autre méthode d’installation, tout est là |
•.Configurez SSH
Génération d’une paire de clés SSH
ssh-keygen -b 4096 -t rsa -f /root/.ssh/id_rsa_restic -q -N ""
Création du fichier de configuration SSH
cat <<EOCONF >> ~/.ssh/config
Host mytargetserver
Hostname mytargetserver.mytargetdomain.tld
Port 2222
User mytargetuser
IdentityFile /root/.ssh/id_rsa_restic
EOCONF
•.Copiez la clé ssh sur le serveur cible
ssh-copy-id -i /root/.ssh/id_rsa_restic mytargetserver
Maintenant qu’on a configuré nos serveurs source et de destination, on veut être sûr que restic sait faire des sauvegardes entre les deux.
Sur mysourceserver en tant que root:
Essai d’initialisation de dépôt sur mytargetserver depuis mysourceserver
restic -r sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/test-repository init
Restic devrait vous demander un mot de passe (mettez ce que vous voulez) et terminer sans erreur.
Il est temps de créer le script qui va sauvegarder l’ensemble de notre instance
•.Créez un fichier /etc/yunohost/hooks.d/backup_method/05-myrestic avec ce contenu:
#!/bin/bash
set -e
RESTIC_PASSWORD="mysupersecretpassword" # changez le mot de passe MAIS ne le perdez pas, il est irrécupérable!
RESTIC_REPOSITORY_BASE=sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld
RESTIC_COMMAND=/usr/local/bin/restic
do_need_mount() {
work_dir="$1"
name="$2"
repo="$3"
size="$4"
description="$5"
export RESTIC_PASSWORD
export RESTIC_REPOSITORY=${RESTIC_REPOSITORY_BASE}/$name
# On essaie de lister les snapshots, sinon on initialise le dépôt
$RESTIC_COMMAND list snapshots || $RESTIC_COMMAND init
}
do_backup() {
work_dir="$1"
name="$2"
repo="$3"
size="$4"
description="$5"
export RESTIC_PASSWORD
export RESTIC_REPOSITORY=${RESTIC_REPOSITORY_BASE}/$name
LOGFILE=/var/log/backup_restic.log
ERRFILE=/var/log/backup_restic.err
current_date=$(date +"%d_%m_%y_%H:%M")
pushd $work_dir
$RESTIC_COMMAND backup ./ >> $LOGFILE 2>> $ERRFILE
return_code="$?"
popd
# On ne nettoie que si la sauvegarde s'est bien passée
if [ "$return_code" -eq "0" ];then
$RESTIC_COMMAND forget --keep-daily 7 --keep-weekly 8 --keep-monthly 12 >> $LOGFILE 2>> $ERRFILE
fi
}
work_dir=$2
name=$3
size=$5
description=$6
case "$1" in
need_mount)
do_need_mount $work_dir $name $repo $size $description
;;
backup)
do_backup $work_dir $name $repo $size $description
;;
mount)
do_need_mount $work_dir $name $repo $size $description
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0
•.Rendez le script exécutable et limitez-y l’accès puisqu’il contient des informations secrètes
chmod u=rwx,go= /etc/yunohost/hooks.d/backup_method/05-myrestic
•.Testez le script
rm -rf /tmp/test-backup/; mkdir /tmp/test-backup; yunohost backup create --system conf_ldap -n conf_ldap --methods myrestic --debug -r -o /tmp/test-backup; rm -rf /tmp/test-backup
Ne passez à l’étape suivante que si cette commande s’est exécutée sans erreurs.
Il peut subsiter des avertissemnts (Warning), celui-ci peut être ignoré par exemple:
Fatal: unable to open config file: Lstat: file does not exist
Is there a repository at the following location?
sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/xxxx
C’est ce que restic affiche quand on essaie d’accéder à un dépôt non initialisé.
| Il reste quelques modifications à apporter à ce script selon moi:
|
Puisqu’on sait que notre script de sauvegarde fonctionne, on peut le planifier. La première sauvegarde peut être très longue, ça dépendra du volume de données à transférer. Les sauvegardes suivantes seront beaucoup plus rapides grâce à la déduplication.
•.créez un fichier /root/yunohost-99-backup avec ce contenu:
#!/bin/bash
LOCK_FILE=/tmp/yunohost-99-backup.lock
if [ -f "$LOCK_FILE" ];then
echo "Backup already launched by process $(grep '.*' $LOCK_FILE), canceling this one" >&2
exit 1
fi
echo $$ > "$LOCK_FILE"
if yunohost -v | grep "version: 2." > /dev/null; then
ignore_apps="--ignore-apps"
ignore_system="--ignore-system"
else
ignore_apps=""
ignore_system=""
fi
filter_hooks() {
ls /usr/share/yunohost/hooks/backup/ /etc/yunohost/hooks.d/backup/ | grep "\-$1_" | cut -d"-" -f2 | uniq
}
# Backup system part conf
yunohost backup create $ignore_apps -n auto_conf --methods myrestic --system $(filter_hooks conf)
# Backup system data
yunohost backup create $ignore_apps -n auto_data --methods myrestic --system $(filter_hooks data)
# Backup all apps independently
for app in $(yunohost app list --installed -b | grep id: | cut -d: -f2); do
backup_methods=$(yunohost app setting $app backup_methods)
if [ -z "$backup_methods" ]; then
backup_methods=myrestic
fi
if [ "$backup_methods" != "none" ]; then
yunohost backup create $ignore_system -n auto_$app --methods $backup_methods --apps $app
fi
done
rm "$LOCK_FILE"
•.Rendez-le exécutable
chmod +x /etc/cron.daily/yunohost-99-backup
J’ai apporté quelques modifications au script d’origine:
•.J’utilise un fichier de verrou pour éviter le lancement concurrent de plusieurs sauvegardes
•.Je n’ai pas planifié directement ce script pour la raison qui suit
J’ai remarqué que la sauvegarde de gitlab bloquait car elle attendait que je réponde à une question par un "y". J’ai cherché dans yunohost backup --help pour savoir comment y répondre sans succès. J’ai essayé quelques astuces avec la commande yes ou un simple echo "y" passé à la commande de backup par un pipe, même résultat. Il fallait absolument que la sauvegarde se fasse sans interaction, j’ai donc utilisé le programme expect pour répondre à la question pour moi. Ça a l’avantage d’être sûr de la question à laquelle on répond
Pour info la question est une demande de confirmation avant de prendre un peu plus d’espace disque que prévu temporairement pour faire la sauvegarde. Si vous êtes juste en place ça peut poser problème.
Voilà comment faire:
•.Install expect
apt install expect -y
•.Créer un fichier /etc/cron.daily/yunohost-99-backup-answerbot avec ce contenu
#!/usr/bin/expect -f
set timeout -1
spawn /root/yunohost-99-backup
expect -re "Some files couldn't be prepared.*Do you agree?"
send -- "y\r"
expect eof
Ce script va lancer le script de sauvegarde et répondre par "y" quand on lui demandera.
Vous pouriez avoir envie (ou besoin) de restaurer des données d’une sauvegarde (c’est tout l’intérêt :p)
Je vous renvoie à la documentation officielle pour les détails des commandes.
Voici un simple exemple de restauration pour l’application Piwigo
•.Listez les snapshots existants
restic -r sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/auto_piwigo snapshots
# enter password for repository:
# repository xxxxxx opened successfully, password is correct
# created new cache in /home/mytargetuser/.cache/restic
# ID Time Host Tags Paths
# -------------------------------------------------------------------------------------------------------------------
# yyyyyyyy 2020-02-10 22:03:22 mysourceserver.mysourcedomain.tld /home/yunohost.backup/tmp/auto_piwigo
# -------------------------------------------------------------------------------------------------------------------
# 1 snapshots
•.Restaurez à partir du snapshot yyyyyyyy
mkdir /tmp/restore
restic -r sftp:mytargetserver:/home/backup/mysourceserver.mysourcedomain.tld/auto_piwigo restore yyyyyyyy --target /tmp/restore
# enter password for repository:
# repository xxxxxx opened successfully, password is correct
# restoring <Snapshot yyyyyyyy of [/home/yunohost.backup/tmp/auto_piwigo] at 2020-02-10 22:03:22.602905984 +0100 CET by root@mysourceserver.mydomain.tld to /tmp/restore
•.Vérifiez que vos fichiers se trouvent bien dans le répertoire de restauration temporaire, référez-vous à la documentation de Yunohost ou du paquet de l’application pour savoir où et quels fichiers restaurer.
tree /tmp/restore/ -L 4
# /tmp/restore/
# ├── apps
# │ └── piwigo
# │ ├── backup
# │ │ ├── db.sql
# │ │ ├── etc
# │ │ ├── home
# │ │ └── var
# │ └── settings
# │ ├── conf
# │ ├── manifest.json
# │ ├── scripts
# │ ├── settings.yml
# │ └── status.json
# ├── backup.csv
# └── info.json
#
# 9 directories, 6 files